/*
* Copyright 2010 Pavel Kozhin 
*
* Licensed under the Apache License, Version 2.0 (the "License"); 
* you may not use this file except in compliance with the License. 
* You may obtain a copy of the License at 
* 
* http://www.apache.org/licenses/LICENSE-2.0
* 
* Unless required by applicable law or agreed to in writing, software 
* distributed  under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
* See the License for the specific language governing permissions and 
* limitations under the License.
*
* Author: Pavel Kozhin.
*/

package org.etherframework.behaviour.rules.context
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
	
	import org.etherframework.core.ether_internal;
	
	use namespace ether_internal;
	
	[Bindable]
	public final class Context extends EventDispatcher implements IContext
	{
		private var isPermitted:Boolean = false;
		
		internal var outputs:Array;
		
		public function Context(target:IContextual, parent:IContext, initiator:Object, 
								outputs:Array, kind:String = "init", value:* = null)
		{
			super();
			
			_target = target;
			_parameters = new Parameters();
			_parent = parent;
			_source = new ContextSource(initiator, new ContextData(kind, value));
			this.outputs = outputs;
		}
		
		private var _parent:IContext;
		
		public function get parent():IContext
		{
			return _parent;
		}
		
		private var _source:ContextSource;
		
		public function get source():ContextSource
		{
			return _source;
		}
		
		private var _output:ContextData;
		
		public function get output():ContextData
		{
			return _output;
		}
		
		private var _target:IContextual = null;
		
		[Bindable(event="propertyChanged")]
		public function get target():IContextual
		{
			return _target;
		}
		
		private var _currentChild:IContext;
		
		public function get currentChild():IContext
		{
			return _currentChild;
		}
		
		public function set currentChild(value:IContext):void
		{
			_currentChild = value;
		}
		
		private var _lastChild:IContext;
		
		public function get lastChild():IContext
		{
			return _lastChild;
		}
		
		public function set lastChild(value:IContext):void
		{
			_lastChild = value;
		}
		
		private var _children:Array = [];
		
		public function get children():Array
		{
			return _children;
		}
		
		public function set children(value:Array):void
		{
			_children = value;
		}
		
		public function setOutput(kind:String = "output", value:* = null):void
		{
			if (_output)
				return;
			
			_output = new ContextData(kind, value);
			outputs.push(_output);
		}
		
		public function open():void
		{
			if (_opened)
				return;
			
			_opened = true;
			isPermitted = true;
			dispatchEvent(new ContextEvent(ContextEvent.OPEN));
			isPermitted = false;
		}
		
		public function close():void
		{
			if (_closed)
				return;
			
			_closed = true;
			isPermitted = true;
			dispatchEvent(new ContextEvent(ContextEvent.CLOSE));
			isPermitted = false;
		}
		
		private var _opened:Boolean = false;
		
		public function get opened():Boolean
		{
			return _opened;
		}
		
		private var _closed:Boolean = false;
		
		public function get closed():Boolean
		{
			return _closed;
		}
		
		private var _parameters:Parameters = null;
		
		public function get parameters():Parameters
		{
			return _parameters;
		}
		
		public function get lastOutput():ContextData
		{
			return outputs[outputs.length - 1];
		}
		
		override public function dispatchEvent(event:Event):Boolean
		{
			return (isPermitted) ? super.dispatchEvent(event) : false;
		}
		
		public function newInstance(target:IContextual, parent:IContext, initiator:Object, 
									kind:String = "init", value:* = null):IContext
		{
			return new Context(target, parent, initiator, Context(parent).outputs, kind, value);
		}
	}
}